package com.heima.wemedia.service.impl;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.heima.apis.article.IArticleClient;
import com.heima.common.aliyun.GreenImageScan;
import com.heima.common.aliyun.GreenTextScan;
import com.heima.common.tess4j.Tess4jClient;
import com.heima.file.service.FileStorageService;
import com.heima.model.article.dto.ArticleDto;
import com.heima.model.common.dtos.ResponseResult;
import com.heima.model.wemedia.pojos.WmChannel;
import com.heima.model.wemedia.pojos.WmNews;
import com.heima.model.wemedia.pojos.WmSensitive;
import com.heima.model.wemedia.pojos.WmUser;
import com.heima.utils.common.SensitiveWordUtil;
import com.heima.wemedia.mapper.WmChannelMapper;
import com.heima.wemedia.mapper.WmNewsMapper;
import com.heima.wemedia.mapper.WmSensitiveMapper;
import com.heima.wemedia.mapper.WmUserMapper;
import com.heima.wemedia.service.WmNewsAutoScanService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import java.util.*;
import java.util.stream.Collectors;

@Service
@Slf4j
@Transactional
public class WmNewsAutoScanServiceImpl implements WmNewsAutoScanService {
    @Autowired
    private WmNewsMapper wmNewsMapper;
    @Autowired
    private GreenTextScan textScan;
    @Autowired
    private GreenImageScan imageScan;
    @Autowired
    private FileStorageService fileStorageService;
    /**
     * 自定义文章审核
     * @param id 自媒体文章id
     */
    @Override
    //@Async   //开启异步审核
    public void autoScanWmNews(Integer id) {

        //1.查询自媒体文章
        LambdaQueryWrapper<WmNews> wrapper=new LambdaQueryWrapper<>();
        wrapper.eq(id!=null,WmNews::getId,id);
        WmNews wmNews = wmNewsMapper.selectOne(wrapper);
        if (wmNews==null){
            throw new RuntimeException("WmNewsAutoScanServiceImpl-->查询失败");
        }
        //判断文章状态   等待审核状态
        if (wmNews.getStatus().equals(WmNews.Status.SUBMIT.getCode())){
            Map<String,Object> contentAndImages = getContentAndImages(wmNews);
            //获取文章内容
            String content = (String) contentAndImages.get("content");
            //文章敏感词过滤  有敏感词直接return
            if (!checkSensitive(wmNews,content)) return;
            //2.自媒体文章审核  阿里云审核
            //判断如果转人工或者审核失败  直接结束
            if (!checkContent(wmNews, contentAndImages)) return;
            //3.自媒体图片审核  阿里云审核
            //判断如果转人工或者审核失败  直接结束
            if (!checkImages(wmNews,contentAndImages)) return;
            //4.审核成功   提交数据

            ResponseResult responseResult = saveArticle(wmNews);
            if (responseResult.getCode()==200){
                wmNews.setArticleId((Long) responseResult.getData());
                updateNews(wmNews,WmNews.Status.PUBLISHED.getCode(),"审核成功");
            }
        }
    }
    /**
     * 文章敏感词过滤
     * @param wmNews
     * @param contentAndImages
     * @return
     */
    @Autowired
    private WmSensitiveMapper mapper;

    private boolean checkSensitive(WmNews wmNews, String content) {
        boolean flag=true;
        //获取敏感词
        LambdaQueryWrapper<WmSensitive> wrapper =new LambdaQueryWrapper<>();
        wrapper.select(WmSensitive::getSensitives);
        List<WmSensitive> listSensitive = mapper.selectList(wrapper);
        List<String> sensitiveList = listSensitive.stream().map(WmSensitive::getSensitives).collect(Collectors.toList());
        //初始化敏感词库
        SensitiveWordUtil.initMap(sensitiveList);
        //检测文章是否包含敏感词
        Map<String, Integer> map = SensitiveWordUtil.matchWords(content);
        if (map.size()>0){
            updateNews(wmNews,WmNews.Status.FAIL.getCode(),"文章中包含敏感词："+map);
            flag=false;
        }
        return flag;
    }

    /**
     * 保存文章
     * @param wmNews
     */
    @Autowired
    private WmChannelMapper wmChannelMapper;
    @Autowired
    private IArticleClient articleClient;
    @Autowired
    private WmUserMapper wmUserMapper;
    public ResponseResult saveArticle(WmNews wmNews) {

        ArticleDto articleDto=new ArticleDto();
        BeanUtils.copyProperties(wmNews,articleDto);
        //文章布局
        articleDto.setLayout(wmNews.getType());
        //文章所属频道   根据id查询name
        WmChannel wmChannel = wmChannelMapper.selectById(wmNews.getChannelId());
        if (wmChannel!=null){
            articleDto.setChannelName(wmChannel.getName());
        }
        //根据userId查询出作者id和name
        WmUser wmUser = wmUserMapper.selectById(wmNews.getUserId());
        if (wmUser!=null){
            articleDto.setAuthorId(Long.valueOf(wmUser.getApAuthorId()));
            articleDto.setAuthorName(wmUser.getName());
        }
        //设置文章ID
        if(wmNews.getArticleId()!=null){
            articleDto.setId(wmNews.getArticleId());
        }
        //创建时间
        articleDto.setCreatedTime(new Date());
        //feign调用远程微服务
        ResponseResult result = articleClient.saveArticle(articleDto);
        return result;
    }

    /**
     * 审核图片
     * @param wmNews
     * @param contentAndImages
     * @return
     */
    @Autowired
    private Tess4jClient tess4jClient;
    private boolean checkImages(WmNews wmNews,Map<String, Object> contentAndImages) {
        //1.通过URL查询minIO自媒体图片  并保存到数组集合中
        boolean flag=true;
        //集合用于保存图片信息
        List<byte[]> imagesList=new ArrayList<>();
        Set<String> images = (Set<String>)contentAndImages.get("images");
        //如果没有图片  直接返回  不用校验
        if (images==null||images.size()==0) return flag;
        //循环遍历图片的URL   从minIo中获取图片
        try{
            for (String image : images) {
                byte[] bytes = fileStorageService.downLoadFile(image);
                //将图片从字节数组转变为BufferedImage
                ByteArrayInputStream in=new ByteArrayInputStream(bytes);
                BufferedImage read = ImageIO.read(in);
                //创建OCR对象
                //识别图中文字
                String result = tess4jClient.doOCR(read);
                //判断有无敏感词
                boolean isSensitive = checkSensitive(wmNews, result);
                if (!isSensitive) {
                    return isSensitive;
                }
                //将获得的图片保存到集合
                imagesList.add(bytes);
            }
        }catch (Exception e){
            e.printStackTrace();
        }


        //2.图片  阿里云审核
        if(imagesList!=null&&imagesList.size()>0){
            try {
                Map map = imageScan.imageScan(imagesList);
                //4.1审核不通过
                if (map.get("suggestion").equals("block")){
                    updateNews(wmNews,WmNews.Status.FAIL.getCode(),"图片中包含违规信息");
                    flag=false;
                }
                if (map.get("suggestion").equals("block")){
                    updateNews(wmNews,WmNews.Status.ADMIN_AUTH.getCode(),"需要人工审核");
                    flag=false;
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        return flag;
    }

    /**
     * 审核文章内容和标题
     * @param wmNews
     * @param contentAndImages
     * @return
     */
    private boolean checkContent(WmNews wmNews, Map<String, Object> contentAndImages) {
        boolean flag=true;
        if (StringUtils.isBlank((String) contentAndImages.get("content"))){
            return flag;
        }
        try {
            //进行审核
            Map contentMap = textScan.greeTextScan((String) contentAndImages.get("content"));
            if (contentMap!=null){
                //如果被阻止
                if (contentMap.get("suggestion").equals("block")){
                    updateNews(wmNews,WmNews.Status.FAIL.getCode(),"当前内容存在违规内容");
                    flag=false;
                }
                //需要人工审核
                if (contentMap.get("suggestion").equals("review")){
                    updateNews(wmNews,WmNews.Status.ADMIN_AUTH.getCode(),"内容需要人工审核");
                    flag=false;
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return flag;
    }

    /**
     * 根据原因更新数据库
     * @param wmNews
     * @param status
     * @param reason
     */
    public void updateNews(WmNews wmNews,Short status,String reason) {
        wmNews.setStatus(status);
        wmNews.setReason(reason);
        wmNewsMapper.updateById(wmNews);
    }

    /**
     * 获得文章内容和图片  封装为一个Map集合
     * 内容包含标题
     * @param wmNews
     * @return
     */
    private Map<String,Object> getContentAndImages(WmNews wmNews) {
        Map<String,Object> contentAndImages=new HashMap<>();
        //获取文章内容和图片
        StringBuilder contentBuilder=new StringBuilder();
        Set<String> images=new HashSet<>();
        //判断内容不为空
        if (StringUtils.isNotBlank(wmNews.getContent())){
            //解析文章内容
            List<Map> maps = JSON.parseArray(wmNews.getContent(), Map.class);
            for (Map map : maps) {
                if (map.get("type").equals("text")){
                    contentBuilder.append(map.get("value"));
                }
                if (map.get("type").equals("image")){
                    images.add((String) map.get("value"));
                }
            }
        }
        if (StringUtils.isNotBlank(wmNews.getTitle())){
            contentBuilder.append(wmNews.getTitle());
        }
        //解析封面图片  放入set集合
        if (StringUtils.isNotBlank(wmNews.getImages())){
            String[] image = wmNews.getImages().split(",");
            images.addAll(Arrays.asList(image));
        }
        contentAndImages.put("content",contentBuilder.toString());
        contentAndImages.put("images",images);
        return contentAndImages;
    }

}

